﻿
using BToolkit.ExeUtils;
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace BToolkit
{
    [AddComponentMenu("BToolkit/BButton")]
    public class BButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler
    {
        public enum Transition { None, Scale, Color, Texture }
        [System.Serializable]
        public class ButtonUnityEvent : UnityEvent<int, string> { }

        internal void OnPointerClick(object onClick)
        {
            throw new NotImplementedException();
        }

        public int index;
        public object param;
        public float canTriggerInterval = 1;
        public AudioClip sound;
        public bool isDownSound = true;
        public bool isClickSound = true;
        public bool listenKeyBack;
        public RectTransform rectTransform { get { return transform as RectTransform; } }
        Action onDown, onUp, onClick, onDoubleClick;
        Action<int> onDownIntParam, onUpIntParam, onClickIntParam, onDoubleIntClickParam;
        Action<object> onDownStrParam, onUpStrParam, onClickStrParam, onDoubleStrClickParam;
        Action<int, object> onDown2Param, onUp2Param, onClick2Param, onDouble2ClickParam;
        float canDownTime, canUpTime, canClickTime, canDoubleClickTime, doubleClickTime;
        //此两个属性用于存储多个监听Back键的按钮同时存在场景中时，按照创建的先后倒序执行
        BButton previousBButton;
        static BButton lastCreateBButton;
        int currPointerId = -1;

        //点击变换效果
        public Transition transition = Transition.Scale;
        public MaskableGraphic transTarget;
        public float pressScale = 0.98f;
        public Color pressColor = new Color(0.95f, 0.95f, 0.95f, 1);
        public Texture2D pressTexture;
        Sprite pressSprite;
        Color colorDefault;
        Sprite defaultSprite;
        Texture defaultTexture;
        Vector3 defaultScale;

        void OnDestroy()
        {
            if (listenKeyBack)
            {
                if (lastCreateBButton == this)
                {
                    lastCreateBButton = previousBButton;
                }
            }
        }

        void Awake()
        {
            if (listenKeyBack)
            {
                previousBButton = lastCreateBButton;
                lastCreateBButton = this;
            }

            //点击变换效果
            if (!transTarget)
            {
                transTarget = GetComponent<MaskableGraphic>();
            }
            if (transTarget)
            {
                if (transTarget is Image)
                {
                    defaultSprite = (transTarget as Image).sprite;
                }
                else if (transTarget is RawImage)
                {
                    defaultTexture = (transTarget as RawImage).texture;
                }
                colorDefault = transTarget.color;
            }
        }

        void OnEnable()
        {
            canDownTime = 0;
            canUpTime = 0;
            canClickTime = 0;
            canDoubleClickTime = 0;
        }

        void Update()
        {
            if (listenKeyBack)
            {
                if (Input.GetKeyDown(KeyCode.Escape))
                {
                    if (DialogAlert.isShowing || DialogConfirm.isShowing)
                    {
                        return;
                    }
                    if (lastCreateBButton == this)
                    {
                        if (onClick != null) onClick.Invoke();
                    }
                }
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            if (enabled)
            {
                if (canDownTime < Time.time)
                {
                    canDownTime = Time.time + canTriggerInterval;
                    if (onDown != null)
                    {
                        onDown.Invoke();
                        if (isDownSound) PlaySound();
                    }
                    if (onDownIntParam != null)
                    {
                        onDownIntParam.Invoke(index);
                        if (isDownSound) PlaySound();
                    }
                    if (onDownStrParam != null)
                    {
                        onDownStrParam.Invoke(param);
                        if (isDownSound) PlaySound();
                    }
                    if (onDown2Param != null)
                    {
                        onDown2Param.Invoke(index, param);
                        if (isDownSound) PlaySound();
                    }

                    //点击变换效果
                    if (transTarget)
                    {
                        switch (transition)
                        {
                            case Transition.Scale:
                                if (defaultScale == Vector3.zero)
                                {
                                    defaultScale = transTarget.transform.localScale;
                                }
                                transTarget.transform.localScale = defaultScale * pressScale;
                                break;
                            case Transition.Color:
                                transTarget.color = pressColor;
                                break;
                            case Transition.Texture:
                                if (transTarget is Image)
                                {
                                    if (!pressSprite)
                                    {
                                        pressSprite = Sprite.Create(pressTexture, new Rect(0, 0, pressTexture.width, pressTexture.height), new Vector2(0.5f, 0.5f));
                                    }
                                    (transTarget as Image).sprite = pressSprite;
                                }
                                else if (transTarget is RawImage)
                                {
                                    (transTarget as RawImage).texture = pressTexture;
                                }
                                break;
                        }
                    }
                }
                currPointerId = eventData.pointerId;
            }
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            bool canExecUp = true;
            if (!Application.isEditor && Application.platform != RuntimePlatform.WindowsPlayer)
            {
                canExecUp = (currPointerId == eventData.pointerId);
            }
            if (canExecUp)
            {
                if (canUpTime < Time.time)
                {
                    canUpTime = Time.time + canTriggerInterval;
                    if (onUp != null)
                    {
                        onUp.Invoke();
                    }
                    if (onUpIntParam != null)
                    {
                        onUpIntParam.Invoke(index);
                    }
                    if (onUpStrParam != null)
                    {
                        onUpStrParam.Invoke(param);
                    }
                    if (onUp2Param != null)
                    {
                        onUp2Param.Invoke(index, param);
                    }
                }
                currPointerId = -1;

                //点击变换效果
                if (transTarget)
                {
                    switch (transition)
                    {
                        case Transition.Scale:
                            transTarget.transform.localScale = defaultScale;
                            break;
                        case Transition.Color:
                            transTarget.color = colorDefault;
                            break;
                        case Transition.Texture:
                            if (transTarget is Image)
                            {
                                (transTarget as Image).sprite = defaultSprite;
                            }
                            else if (transTarget is RawImage)
                            {
                                (transTarget as RawImage).texture = defaultTexture;
                            }
                            break;
                    }
                }
            }
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            if (enabled)
            {
                if (canClickTime < Time.time)
                {
                    canClickTime = Time.time + canTriggerInterval;
                    if (onClick != null)
                    {
                        onClick.Invoke();
                        if (isClickSound) PlaySound();
                    }
                    if (onClickIntParam != null)
                    {
                        onClickIntParam.Invoke(index);
                        if (isClickSound) PlaySound();
                    }
                    if (onClickStrParam != null)
                    {
                        onClickStrParam.Invoke(param);
                        if (isClickSound) PlaySound();
                    }
                    if (onClick2Param != null)
                    {
                        onClick2Param.Invoke(index, param);
                        if (isClickSound) PlaySound();
                    }
                }

                if (doubleClickTime > Time.time)
                {
                    doubleClickTime = 0;
                    if (canDoubleClickTime < Time.time)
                    {
                        canDoubleClickTime = Time.time + canTriggerInterval;
                        if (onDoubleClick != null)
                        {
                            onDoubleClick.Invoke();
                            PlaySound();
                        }
                        if (onDoubleIntClickParam != null)
                        {
                            onDoubleIntClickParam.Invoke(index);
                            PlaySound();
                        }
                        if (onDoubleStrClickParam != null)
                        {
                            onDoubleStrClickParam.Invoke(param);
                            PlaySound();
                        }
                        if (onDouble2ClickParam != null)
                        {
                            onDouble2ClickParam.Invoke(index, param);
                            PlaySound();
                        }
                    }
                }
                else
                {
                    doubleClickTime = Time.time + 0.5f;
                }

            }
        }

        void PlaySound()
        {
            if (sound)
            {
                SoundPlayer.PlayAndDestroy(0, sound);
            }
            else
            {
                OutAudioPlayer.PlaySingleSound(MainController.dataPath + "/Sounds/click", true, false);
            }
        }

        public void AddDown(Action action)
        {
            onDown += action;
        }
        public void RemoveDown(Action action)
        {
            onDown -= action;
        }

        public void AddUp(Action action)
        {
            onUp += action;
        }
        public void RemoveUp(Action action)
        {
            onUp -= action;
        }

        public void AddClick(Action action)
        {
            onClick += action;
        }
        public void RemoveClick(Action action)
        {
            onClick -= action;
        }

        public void AddDoubleClick(Action action)
        {
            onDoubleClick += action;
        }
        public void RemoveDoubleClick(Action action)
        {
            onDoubleClick -= action;
        }

        public void AddDown(Action<int> action)
        {
            onDownIntParam += action;
        }
        public void RemoveDown(Action<int> action)
        {
            onDownIntParam -= action;
        }

        public void AddUp(Action<int> action)
        {
            onUpIntParam += action;
        }
        public void RemoveUp(Action<int> action)
        {
            onUpIntParam -= action;
        }

        public void AddClick(Action<int> action)
        {
            onClickIntParam += action;
        }
        public void RemoveClick(Action<int> action)
        {
            onClickIntParam -= action;
        }

        public void AddDoubleClick(Action<int> action)
        {
            onDoubleIntClickParam += action;
        }
        public void RemoveDoubleClick(Action<int> action)
        {
            onDoubleIntClickParam -= action;
        }

        public void AddDown(Action<object> action)
        {
            onDownStrParam += action;
        }
        public void RemoveDown(Action<object> action)
        {
            onDownStrParam -= action;
        }

        public void AddUp(Action<object> action)
        {
            onUpStrParam += action;
        }
        public void RemoveUp(Action<object> action)
        {
            onUpStrParam -= action;
        }

        public void AddClick(Action<object> action)
        {
            onClickStrParam += action;
        }
        public void RemoveClick(Action<object> action)
        {
            onClickStrParam -= action;
        }

        public void AddDoubleClick(Action<object> action)
        {
            onDoubleStrClickParam += action;
        }
        public void RemoveDoubleClick(Action<object> action)
        {
            onDoubleStrClickParam -= action;
        }

        public void AddDown(Action<int, object> action)
        {
            onDown2Param += action;
        }
        public void RemoveDown(Action<int, object> action)
        {
            onDown2Param -= action;
        }

        public void AddUp(Action<int, object> action)
        {
            onUp2Param += action;
        }
        public void RemoveUp(Action<int, object> action)
        {
            onUp2Param -= action;
        }

        public void AddClick(Action<int, object> action)
        {
            onClick2Param += action;
        }
        public void RemoveClick(Action<int, object> action)
        {
            onClick2Param -= action;
        }

        public void AddDoubleClick(Action<int, object> action)
        {
            onDouble2ClickParam += action;
        }
        public void RemoveDoubleClick(Action<int, object> action)
        {
            onDouble2ClickParam -= action;
        }

        /// <summary>
        /// 外部改变缩放值后重设这里的缩放值
        /// </summary>
        public void SetDefaultScale(Vector3 sacle)
        {
            defaultScale = sacle;
        }
    }
}